package io.libp2p.example.chat;

import android.util.Base64;

import com.google.gson.Gson;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import io.libp2p.example.localserver.FileServer;

public class SocketConnect {
    public static final String TAG = "SocketConnect";

    PeerConnectHelper helper;

    String socketId;

    ConnectCallback callback;

    private String targetIp = "127.0.0.1";
    private int targetPort = FileServer.PORT;

    List<String> dataList = new ArrayList<>();

    Socket socket;

    OutputStream outputStream;

    Gson gson = new Gson();

    public interface ConnectCallback{
        void onClose();
    }

    public SocketConnect(PeerConnectHelper helper, String socketId, ConnectCallback callback){
        this.helper = helper;
        this.socketId = socketId;
        this.callback = callback;

        SocketServer.getExecutor().execute(()->start());
    }

    public void start(){
        try {
            socket = new Socket(targetIp, targetPort);

            outputStream = socket.getOutputStream();

            for(String base64: dataList){
                byte buf[] = Base64.decode(base64, Base64.DEFAULT);
                outputStream.write(buf);
            }

            InputStream inputStream = socket.getInputStream();

            byte buf[] = new byte[SocketServer.BUF_SIZE];
            int len;

            while ((len = inputStream.read(buf)) != -1){
                String base64 = Base64.encodeToString(buf, 0, len, Base64.DEFAULT);
                DataCmd dataCmd = DataCmd.parseFileData(socketId, DataCmd.CMD_SOCKET_CLIENT, base64);
                String json = gson.toJson(dataCmd);
                helper.sendDataChannel(json);
            }

            MyLog.I(TAG, "----------->readData from NanoHttpD END");

            sendClientCLose();

            onClose();

            socket.close();
        } catch (IOException e) {
            onClose();
            MyLog.E(TAG, "readData from NanoHttpD"+socketId+" IOException "+e);
        }
    }

    public void writeDate(DataCmd dataCmd){
        if(outputStream == null){
            dataList.add(dataCmd.zbase64);
        }else {
            SocketServer.getExecutor().execute(() -> {
                try {
                    byte buf[] = Base64.decode(dataCmd.zbase64, Base64.DEFAULT);
                    outputStream.write(buf);
                } catch (IOException e) {
                    onClose();
                    MyLog.E(TAG, "writeData to NanoHttpD IOException "+e);
                }
            });
        }
    }

    public void close(){
        MyLog.I(TAG, "close from client command, socketId="+socketId);

        if(socket != null){
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    void onClose(){
        MyLog.E(TAG, "onClose socketId="+socketId);

        if(callback != null){
            callback.onClose();
        }
    }

    void sendClientCLose(){
        DataCmd dataCmd = DataCmd.parseFileData(socketId, DataCmd.CMD_CLIENT_CLOSE);
        String json = gson.toJson(dataCmd);
        helper.sendDataChannel(json);
    }

}
